
class Vue {
  // Vue的做法： 先转AST树 -> 虚拟节点 -> 真实节点
  // 简单实现: 直接使用真实节点
  /**
   * 1. 代理数据(数据劫持)
   * 2. 初始化DOM
   * 3. 初始化视图
   * 4. 事件处理函数的绑定
   * 5. 改变数据的同时，改变DOM
   */
  constructor(options) {
    const { el, data, methods } = options;

    this.$el = document.querySelector(el);
    this.$data = data();
    this.$methods = methods;
    this.showPool = new Map();
    this.eventPool = new Map();

    this.init();
  }

  init() {
    this.initData();
    this.initDom(this.$el);
    this.initView(this.showPool);
    this.initEvent(this.eventPool);
  }

  initData() {
    const _this = this;

    for (let key in this.$data) {
      Object.defineProperty(this, key, {
        get() {
          return _this.$data[key];
        },
        set(newVal) {
          _this.$data[key] = newVal;
          _this.domChange(key, _this.showPool);
        }
      })
    }
  }

  initDom(el) { // 绑定dom
    const _childNodes = el.childNodes;

    if (!_childNodes.length) return;

    _childNodes.forEach(item => {
      if (item.nodeType === 1) { // 如果是元素节点
        const _vIf = item.getAttribute('v-if');
        const _vShow = item.getAttribute('v-show');
        const _vEvent = item.getAttribute('@click');
        // console.log(_vIf, _vShow, _vEvent)
        if (_vIf) {
          this.showPool.set(item, {
            type: 'if',
            key: _vIf,
            show: this.$data[_vIf]
          });
        } else if (_vShow) {
          this.showPool.set(item, {
            type: 'show',
            key: _vShow,
            show: this.$data[_vShow]
          });
        }

        if (_vEvent) {
          this.eventPool.set(item, this.$methods[_vEvent]);
        }
      }

      item.childNodes && this.initDom(item);
    })
  }

  initView(showPool) { // 初始化视图
    this.domChange(null, showPool);
  }

  domChange(key, showPool) {
    // 先初始化
    if (!key) {
      for (let [k, v] of showPool) {
        switch (v.type) {
          case 'if': // 使用占位节点替换显示(Vue方案：注释)
            v.comment = document.createComment('v-if');
            !v.show && k.parentNode.replaceChild(v.comment, k);
            break;
          case 'show':
            !v.show && (k.style.display = 'none');
            break;
          default:
            break;
        }
      }
      return
    }
    // 数据变化时
    for (let [k, v] of showPool) {
      if (v.key === key) {
        switch (v.type) {
          case 'if':
            v.show ? k.parentNode.replaceChild(v.comment, k)
                   : v.comment.parentNode.replaceChild(k, v.comment);
            v.show = !v.show;
            break;
          case 'show':
            v.show ? k.style.display = 'none'
                   : k.style.display = 'block';
            v.show = !v.show;
            break;
          default:
            break;
        }
      }
    }
  }

  initEvent(eventPool) {
    for (let [k, v] of eventPool) {
      k.addEventListener('click', v.bind(this), false);
    }
  }
}
